﻿using Common.AspNetCore.Structs;
using Common.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common.AspNetCore.Utils
{
   public static class AspNetCoreInitUtils
    {
        public static void InitModel()
        {
            DoInitModeType();
        }

        private static void DoInitModeType()
        {
            var files = System.IO.Directory.GetFiles(System.AppContext.BaseDirectory, "*.Models.dll");
            if (files == null || !files.Any())
            {
                return;
            }

            foreach (var file in files)
            {
                var assembly = Assembly.LoadFrom(file);
                if (assembly != null)
                {
                    var types = assembly.GetTypes();
                    foreach (var t in types)
                    {
                        if (!t.IsSubclassOf(typeof(ModelBase)))
                        {
                            continue;
                        }

                        ModelType modelType = new ModelType
                        {
                            Name = t.Name,
                            Type = t
                        };
                        ModelTypeManager.AddModelType(modelType);

                        ModelConfig modelConfig = new ModelConfig
                        {
                            Name = t.Name,
                        };
                        var mca = GetAttributeByType<ModelServiceCodeAttribute>(t);
                        modelConfig.ModuleCode = mca?.ServiceCode;
                        var ena = GetAttributeByType<ModelEntityNameAttribute>(t);
                        modelConfig.EntityName = ena?.EntityName;
                        if (string.IsNullOrEmpty(modelConfig.EntityName) && modelConfig.Name.StartsWith("m_"))
                        {
                            modelConfig.EntityName = "t" + modelConfig.Name.Substring(1);
                        }

                        var aa = GetAttributeByType<ModelModelApiAttribute>(t);
                        modelConfig.ModelApi = aa?.Api;
                        var aa1 = GetAttributeByType<ModelModelOrderApiAttribute>(t);
                        modelConfig.ModelOrderApi = aa1?.Api;
                        var aa2 = GetAttributeByType<ModelModelOrderPageApiAttribute>(t);
                        modelConfig.ModelOrderPageApi = aa2?.Api;
                        var aa3 = GetAttributeByType<ModelModelIdApiAttribute>(t);
                        modelConfig.ModelIdApi = aa3?.Api;

                        foreach (var p in t.GetProperties())
                        {
                            var ida = GetAttributeByProperty<ModelFieldForeignIdAttribute>(p);
                            string idFieldName = ida?.IdFieldName; 
                            var enumNameA = GetAttributeByProperty<ModelFieldEnumNameAttribute>(p);
                            string enumName = enumNameA?.EnumName;
                            ModelFieldConfigBase fieldConfig;
                            if (!string.IsNullOrEmpty(idFieldName))
                            {
                                if (p.PropertyType.IsGenericType && typeof(System.Collections.IEnumerable).IsAssignableFrom(p.PropertyType))
                                {
                                    var genArgs = p.PropertyType.GetGenericArguments();
                                    if (genArgs.Any() && genArgs[0].IsSubclassOf(typeof(ModelBase)))
                                    {
                                        ModelManyNavFieldConfig config = new ModelManyNavFieldConfig
                                        {
                                            Name = p.Name,
                                            IdField = idFieldName,
                                            NavModelName = genArgs[0].Name
                                        };
                                        fieldConfig = config;
                                        modelConfig.AddFieldModelConfig(config);
                                    }
                                }
                                else if (p.PropertyType.IsClass && p.PropertyType != typeof(string))
                                {
                                    ModelNavFieldConfig config = new ModelNavFieldConfig
                                    {
                                        Name = p.Name,
                                        IdField = idFieldName,
                                        NavModelName = p.PropertyType.Name
                                    };
                                    fieldConfig = config;
                                    modelConfig.AddFieldModelConfig(config);
                                }
                            }
                            else if (!string.IsNullOrEmpty(enumName))
                            {
                                ModelEnumFieldConfig config = new ModelEnumFieldConfig
                                {
                                    Name = p.Name,
                                    EnumName = enumName
                                };
                                fieldConfig = config;
                                modelConfig.AddFieldModelConfig(config);
                            }
                            else
                            {
                                ModelFieldConfig config = new ModelFieldConfig
                                {
                                    Name = p.Name,
                                    FieldTypeStr = p.PropertyType.GetNonNummableType().Name
                                };
                                fieldConfig = config;
                                modelConfig.AddFieldModelConfig(config);
                            }
                        }

                        ModelConfigManager.AddModelConfig(modelConfig);
                    }
                }
            }
        }

        private static T GetAttributeByProperty<T>(PropertyInfo property) where T : Attribute
        {
            T attr = null;
            object[] attrs = property.GetCustomAttributes(typeof(T), true);
            if (attrs.Length == 1)
            {
                attr = (T)attrs[0];
            }

            return attr;
        }

        private static T GetAttributeByType<T>(Type type) where T : Attribute
        {
            T attr = null;
            object[] attrs = type.GetCustomAttributes(typeof(T), true);
            if (attrs.Length == 1)
            {
                attr = (T)attrs[0];
            }

            return attr;
        }
    }
}
